home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / chrome_100_percent.pak / Unnamed File 000010.txt < prev    next >
Text File  |  2013-04-03  |  11KB  |  295 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. // This script contains unprivileged javascript APIs related to chrome
  6. // extensions.  It is loaded by any extension-related context, such as content
  7. // scripts or background pages.
  8. // See user_script_slave.cc for script that is loaded by content scripts only.
  9.  
  10.   require('json_schema');
  11.   require('event_bindings');
  12.   var lastError = require('lastError');
  13.   var miscNatives = requireNative('miscellaneous_bindings');
  14.   var CloseChannel = miscNatives.CloseChannel;
  15.   var PortAddRef = miscNatives.PortAddRef;
  16.   var PortRelease = miscNatives.PortRelease;
  17.   var PostMessage = miscNatives.PostMessage;
  18.   var BindToGC = miscNatives.BindToGC;
  19.  
  20.   var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
  21.  
  22.   var processNatives = requireNative('process');
  23.   var manifestVersion = processNatives.GetManifestVersion();
  24.   var extensionId = processNatives.GetExtensionId();
  25.  
  26.   // The reserved channel name for the sendRequest/sendMessage APIs.
  27.   // Note: sendRequest is deprecated.
  28.   chromeHidden.kRequestChannel = "chrome.extension.sendRequest";
  29.   chromeHidden.kMessageChannel = "chrome.extension.sendMessage";
  30.   chromeHidden.kNativeMessageChannel = "chrome.extension.sendNativeMessage";
  31.  
  32.   // Map of port IDs to port object.
  33.   var ports = {};
  34.  
  35.   // Map of port IDs to chromeHidden.onUnload listeners. Keep track of these
  36.   // to free the onUnload listeners when ports are closed.
  37.   var portReleasers = {};
  38.  
  39.   // Change even to odd and vice versa, to get the other side of a given
  40.   // channel.
  41.   function getOppositePortId(portId) { return portId ^ 1; }
  42.  
  43.   // Port object.  Represents a connection to another script context through
  44.   // which messages can be passed.
  45.   function PortImpl(portId, opt_name) {
  46.     this.portId_ = portId;
  47.     this.name = opt_name;
  48.     this.onDisconnect = new chrome.Event();
  49.     this.onMessage = new chrome.Event();
  50.   }
  51.  
  52.   // Sends a message asynchronously to the context on the other end of this
  53.   // port.
  54.   PortImpl.prototype.postMessage = function(msg) {
  55.     // JSON.stringify doesn't support a root object which is undefined.
  56.     if (msg === undefined)
  57.       msg = null;
  58.     PostMessage(this.portId_, chromeHidden.JSON.stringify(msg));
  59.   };
  60.  
  61.   // Disconnects the port from the other end.
  62.   PortImpl.prototype.disconnect = function() {
  63.     CloseChannel(this.portId_, true);
  64.     this.destroy_();
  65.   };
  66.  
  67.   PortImpl.prototype.destroy_ = function() {
  68.     var portId = this.portId_;
  69.  
  70.     this.onDisconnect.destroy_();
  71.     this.onMessage.destroy_();
  72.  
  73.     PortRelease(portId);
  74.     chromeHidden.onUnload.removeListener(portReleasers[portId]);
  75.  
  76.     delete ports[portId];
  77.     delete portReleasers[portId];
  78.   };
  79.  
  80.   chromeHidden.Port = {};
  81.  
  82.   // Returns true if the specified port id is in this context. This is used by
  83.   // the C++ to avoid creating the javascript message for all the contexts that
  84.   // don't care about a particular message.
  85.   chromeHidden.Port.hasPort = function(portId) {
  86.     return portId in ports;
  87.   };
  88.  
  89.   // Hidden port creation function.  We don't want to expose an API that lets
  90.   // people add arbitrary port IDs to the port list.
  91.   chromeHidden.Port.createPort = function(portId, opt_name) {
  92.     if (ports[portId]) {
  93.       throw new Error("Port '" + portId + "' already exists.");
  94.     }
  95.     var port = new PortImpl(portId, opt_name);
  96.     ports[portId] = port;
  97.     portReleasers[portId] = PortRelease.bind(this, portId);
  98.     chromeHidden.onUnload.addListener(portReleasers[portId]);
  99.  
  100.     PortAddRef(portId);
  101.     return port;
  102.   };
  103.  
  104.   // Helper function for dispatchOnRequest.
  105.   function handleSendRequestError(isSendMessage, responseCallbackPreserved,
  106.                                   sourceExtensionId, targetExtensionId) {
  107.     var errorMsg;
  108.     var eventName = (isSendMessage  ?
  109.         "chrome.extension.onMessage" : "chrome.extension.onRequest");
  110.     if (isSendMessage && !responseCallbackPreserved) {
  111.       errorMsg =
  112.           "The " + eventName + " listener must return true if you want to" +
  113.           " send a response after the listener returns ";
  114.     } else {
  115.       errorMsg =
  116.           "Cannot send a response more than once per " + eventName +
  117.           " listener per document";
  118.     }
  119.     errorMsg += " (message was sent by extension " + sourceExtensionId;
  120.     if (sourceExtensionId != targetExtensionId)
  121.       errorMsg += " for extension " + targetExtensionId;
  122.     errorMsg += ").";
  123.     lastError.set(errorMsg);
  124.     console.error("Could not send response: " + errorMsg);
  125.   }
  126.  
  127.   // Helper function for dispatchOnConnect
  128.   function dispatchOnRequest(portId, channelName, sender,
  129.                              sourceExtensionId, targetExtensionId,
  130.                              isExternal) {
  131.     var isSendMessage = channelName == chromeHidden.kMessageChannel;
  132.     var requestEvent = (isSendMessage ?
  133.        (isExternal ?
  134.            chrome.extension.onMessageExternal : chrome.extension.onMessage) :
  135.        (isExternal ?
  136.            chrome.extension.onRequestExternal : chrome.extension.onRequest));
  137.     if (requestEvent.hasListeners()) {
  138.       var port = chromeHidden.Port.createPort(portId, channelName);
  139.       port.onMessage.addListener(function(request) {
  140.         var responseCallbackPreserved = false;
  141.         var responseCallback = function(response) {
  142.           if (port) {
  143.             port.postMessage(response);
  144.             port.destroy_();
  145.             port = null;
  146.           } else {
  147.             // We nulled out port when sending the response, and now the page
  148.             // is trying to send another response for the same request.
  149.               handleSendRequestError(isSendMessage, responseCallbackPreserved,
  150.                                      sourceExtensionId, targetExtensionId);
  151.           }
  152.         };
  153.         // In case the extension never invokes the responseCallback, and also
  154.         // doesn't keep a reference to it, we need to clean up the port. Do
  155.         // so by attaching to the garbage collection of the responseCallback
  156.         // using some native hackery.
  157.         BindToGC(responseCallback, function() {
  158.           if (port) {
  159.             port.destroy_();
  160.             port = null;
  161.           }
  162.         });
  163.           if (!isSendMessage) {
  164.             requestEvent.dispatch(request, sender, responseCallback);
  165.           } else {
  166.             var rv = requestEvent.dispatch(request, sender, responseCallback);
  167.             responseCallbackPreserved =
  168.                 rv && rv.results && rv.results.indexOf(true) > -1;
  169.             if (!responseCallbackPreserved && port) {
  170.               // If they didn't access the response callback, they're not
  171.               // going to send a response, so clean up the port immediately.
  172.               port.destroy_();
  173.               port = null;
  174.             }
  175.           }
  176.       });
  177.       return true;
  178.     }
  179.     return false;
  180.   }
  181.  
  182.   // Called by native code when a channel has been opened to this context.
  183.   chromeHidden.Port.dispatchOnConnect = function(portId, channelName, tab,
  184.                                                  sourceExtensionId,
  185.                                                  targetExtensionId) {
  186.     // Only create a new Port if someone is actually listening for a connection.
  187.     // In addition to being an optimization, this also fixes a bug where if 2
  188.     // channels were opened to and from the same process, closing one would
  189.     // close both.
  190.     if (targetExtensionId != extensionId)
  191.       return false;  // not for us
  192.     if (ports[getOppositePortId(portId)])
  193.       return false;  // this channel was opened by us, so ignore it
  194.  
  195.     // Determine whether this is coming from another extension, so we can use
  196.     // the right event.
  197.     var isExternal = sourceExtensionId != extensionId;
  198.  
  199.     if (tab)
  200.       tab = chromeHidden.JSON.parse(tab);
  201.     var sender = {tab: tab, id: sourceExtensionId};
  202.  
  203.     // Special case for sendRequest/onRequest and sendMessage/onMessage.
  204.     if (channelName == chromeHidden.kRequestChannel ||
  205.         channelName == chromeHidden.kMessageChannel) {
  206.       return dispatchOnRequest(portId, channelName, sender,
  207.                                sourceExtensionId, targetExtensionId,
  208.                                isExternal);
  209.     }
  210.  
  211.     var connectEvent = (isExternal ?
  212.         chrome.extension.onConnectExternal : chrome.extension.onConnect);
  213.     if (connectEvent.hasListeners()) {
  214.       var port = chromeHidden.Port.createPort(portId, channelName);
  215.       port.sender = sender;
  216.       if (manifestVersion < 2)
  217.         port.tab = port.sender.tab;
  218.  
  219.       connectEvent.dispatch(port);
  220.       return true;
  221.     }
  222.     return false;
  223.   };
  224.  
  225.   // Called by native code when a channel has been closed.
  226.   chromeHidden.Port.dispatchOnDisconnect = function(
  227.       portId, connectionInvalid) {
  228.     var port = ports[portId];
  229.     if (port) {
  230.       // Update the renderer's port bookkeeping, without notifying the browser.
  231.       CloseChannel(portId, false);
  232.       if (connectionInvalid) {
  233.         var errorMsg =
  234.             "Could not establish connection. Receiving end does not exist.";
  235.         lastError.set(errorMsg);
  236.         console.error("Port error: " + errorMsg);
  237.       }
  238.       try {
  239.         port.onDisconnect.dispatch(port);
  240.       } finally {
  241.         port.destroy_();
  242.         lastError.clear();
  243.       }
  244.     }
  245.   };
  246.  
  247.   // Called by native code when a message has been sent to the given port.
  248.   chromeHidden.Port.dispatchOnMessage = function(msg, portId) {
  249.     var port = ports[portId];
  250.     if (port) {
  251.       if (msg) {
  252.         msg = chromeHidden.JSON.parse(msg);
  253.       }
  254.       port.onMessage.dispatch(msg, port);
  255.     }
  256.   };
  257.  
  258.   // Shared implementation used by tabs.sendMessage and extension.sendMessage.
  259.   chromeHidden.Port.sendMessageImpl = function(port, request,
  260.                                                responseCallback) {
  261.     if (port.name != chromeHidden.kNativeMessageChannel)
  262.       port.postMessage(request);
  263.  
  264.     if (port.name == chromeHidden.kMessageChannel && !responseCallback) {
  265.       // TODO(mpcomplete): Do this for the old sendRequest API too, after
  266.       // verifying it doesn't break anything.
  267.       // Go ahead and disconnect immediately if the sender is not expecting
  268.       // a response.
  269.       port.disconnect();
  270.       return;
  271.     }
  272.  
  273.     // Ensure the callback exists for the older sendRequest API.
  274.     if (!responseCallback)
  275.       responseCallback = function() {};
  276.  
  277.     port.onDisconnect.addListener(function() {
  278.       // For onDisconnects, we only notify the callback if there was an error
  279.       try {
  280.         if (chrome.runtime.lastError)
  281.           responseCallback();
  282.       } finally {
  283.         port = null;
  284.       }
  285.     });
  286.     port.onMessage.addListener(function(response) {
  287.       try {
  288.         responseCallback(response);
  289.       } finally {
  290.         port.disconnect();
  291.         port = null;
  292.       }
  293.     });
  294.   }
  295.